package org.budo.jdbc.dao.statement.named;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Map;
import java.util.Map.Entry;

import org.budo.jdbc.dao.statement.named.parser.CachedNamedParameterQueryParser;
import org.budo.jdbc.dao.statement.named.parser.DefaultNamedParameterQueryParser;
import org.budo.jdbc.dao.statement.named.parser.NamedParameterQueryParser;

/**
 * @author lmw
 */
public class NamedParameterPreparedStatement {
    private NamedParameterQueryParser namedParameterQueryParser = new CachedNamedParameterQueryParser(new DefaultNamedParameterQueryParser());

    private NamedParameterQuery namedParameterQuery;

    private PreparedStatement preparedStatement;

    public NamedParameterPreparedStatement() {}

    public NamedParameterPreparedStatement(Connection connection, String sql) {
        try {
            this.namedParameterQuery = this.getNamedParameterQueryParser().parseQuery(sql);
            this.preparedStatement = connection.prepareStatement(namedParameterQuery.getParsedSql());
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    public void setParameters(Map<String, Object> parameters) {
        if (null == parameters || parameters.isEmpty()) {
            return;
        }

        try {
            for (Entry<String, Object> entry : parameters.entrySet()) {
                Integer parameterIndex = this.namedParameterQuery.getParameterIndex(entry.getKey());
                this.preparedStatement.setObject(parameterIndex + 1, entry.getValue());
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    public Integer executeUpdate() {
        try {
            return this.preparedStatement.executeUpdate();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    public ResultSet executeQuery() {
        try {
            return this.preparedStatement.executeQuery();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    public NamedParameterQueryParser getNamedParameterQueryParser() {
        return this.namedParameterQueryParser;
    }

    public void close() {
        try {
            this.preparedStatement.close();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
}